#include "ctp.h"

	Manager::Manager()
	{

	}

	bool Manager::load_info()
	{
		try {
			boost::filesystem::path desc_file(ZQDBGetDataDir());
			desc_file.append(STR_MODULE_NAME).append(STR_MODULE_NAME ".json");
			if (boost::filesystem::exists(desc_file)) {
				return XUtil::json_from_file(desc_file, info_);
			}
		}
		catch (...)
		{

		}
		return false;
	}

	void Manager::save_info()
	{
		try {
			boost::system::error_code ec;
			boost::filesystem::path desc_file(ZQDBGetDataDir());
			desc_file.append(STR_MODULE_NAME);
			if (!boost::filesystem::exists(desc_file, ec)) {
				boost::filesystem::create_directories(desc_file, ec);
			}
			desc_file.append(STR_MODULE_NAME ".json");
			XUtil::json_to_file(desc_file, info_);
		}
		catch (...)
		{

		}
	}

	bool Manager::init(const char* xml, int xmlflag)
	{
		LOG4I(STR_MODULE_NAME " ver=%s", CThostFtdcTraderApi::GetApiVersion());

		ASSERT(!ZQDBIsIPC());

		XUtil::cfg_from_xml(xml, xmlflag, cfg_);
		
		boost::filesystem::path data_path(ZQDBGetDataDir()); data_path.append(STR_MODULE_NAME);
		if (!boost::filesystem::exists(data_path))
		{
			boost::filesystem::create_directory(data_path);
		}
		if (ZQDBIsRPC()) {
			if (!load_info()) {
				//先从远程拉取info
				ZQDBRequestHttpGetFile("/" STR_MODULE_NAME "/" STR_MODULE_NAME ".json");
				load_info();
			}
		}
		else {
			load_info();
			if (ZQDBIsServer()) {
				ZQDBRegisterHttpGetFile("/" STR_MODULE_NAME "/" STR_MODULE_NAME ".json");
			}
		}

		LOGXXX_INIT();

		MDMgr::Inst().init();
		TDMgr::Inst().init();

		MODULEINFOEX module = { 0 };
		strcpy(module.Code, STR_MODULE_NAME);
		//strcpy(module.Name, STR_CTP_MODULE);
		strcpy(module.Name, cfg_.get<std::string>("name", STR_MODULE_NAME).c_str());
		module.flags = ZQDB_MODULE_FLAG_MARKET | ZQDB_MODULE_FLAG_TRADE | ZQDB_MODULE_FLAG_EXCHANGE_QH;
		//
		module.sub_all = MDMgr::Inst().is_subscribe_all();
		//
		module.tradingday = info_.get<uint32_t>("tradingday", 0);
		module.closeday = info_.get<uint32_t>("closeday", 0);
		//
		module.notify_cb = [](HZQDB h, ZQDB_NOTIFY_TYPE notify) {
			MDMgr::Inst().HandleNotify(h, notify);
			TDMgr::Inst().HandleNotify(h, notify);
		};
		//
		module.notify = [](ZQDB_MSG* hmsg) {
			zqdb::Msg msg(hmsg, zqdb::Msg::Ref);
			auto reqtype = msg.GetReqType();
			switch (reqtype)
			{
			case com::zqdb::proto::msg::MSG_NOTIFY_MODULE_STATUS:
			case com::zqdb::proto::msg::MSG_NOTIFY_MD_SUBSCRIBE: {
				MDMgr::Inst().notify(msg);
			} break;
			}
		};
		module.request = [](ZQDB_MSG* hmsg) -> int {
			zqdb::Msg msg(hmsg, zqdb::Msg::Ref);
			auto type = msg.GetMsgType();
			auto reqtype = msg.GetReqType();
			switch (type)
			{
			case ZQDB_MSG_NOTIFY: {

			} break;
			case ZQDB_MSG_REQUEST_DO: {
				switch (reqtype)
				{
				case com::zqdb::proto::msg::MSG_REQUEST_DO_TD_USER_LOGIN:
				case com::zqdb::proto::msg::MSG_REQUEST_DO_TD_USER_LOGOUT:
				case com::zqdb::proto::msg::MSG_REQUEST_DO_TD_ORDER_INSERT:
				case com::zqdb::proto::msg::MSG_REQUEST_DO_TD_ORDER_CANCEL: {
					return TDMgr::Inst().request(msg);
				} break;
				case com::zqdb::proto::msg::MSG_REQUEST_DO_MD_SUBSCRIBE: {
					return MDMgr::Inst().request(msg);
				} break;
				}
			} break;
			case ZQDB_MSG_REQUEST_QUERY: {
				return MDMgr::Inst().request(msg);
			} break;
			case ZQDB_MSG_RESPONSE: {
				//
			} break;
			default:
				break;
			}
			return ZQDB_STATUS_INVALID_PARAM;
		};
		module.init_data = [](HZQDB h, PERIODTYPE cycle, ZQDB_MSG* msg, HZQDB base) -> int {
			return MDMgr::Inst().init_data(h, cycle, zqdb::Msg(msg, zqdb::Msg::None), base);
		};
		module.update_data = [](HZQDB h, MDB_FIELD* diff_field, size_t diff_field_num, CODEINFO* data) -> int {
			return MDMgr::Inst().update_data(h, diff_field, diff_field_num, data);
		};
		module.build_data = [](HZQDB h, PERIODTYPE cycle, ZQDB_MSG* msg) -> int {
			return MDMgr::Inst().build_data(h, cycle, zqdb::Msg(msg, zqdb::Msg::None));
		};
		module.exist_data = [](HZQDB h, PERIODTYPE cycle) -> bool {
			return MDMgr::Inst().exist_data(h, cycle);
		};
		module.load_data = [](HZQDB h, PERIODTYPE cycle, ZQDB_MSG** msg) -> int {
			std::string data;
			int ret = MDMgr::Inst().load_data(h, cycle, data);
			if (!data.empty()) {
				*msg = ZQDBMsgParse(data.data(), data.size());
			}
			return ret;
		};
		module.save_data = [](HZQDB h, PERIODTYPE cycle, ZQDB_MSG* msg) -> int {
			return MDMgr::Inst().save_data(h, cycle, zqdb::Msg(msg, zqdb::Msg::None));
		};
		module.close_data = [](HZQDB h, PERIODTYPE cycle) -> int {
			return MDMgr::Inst().close_data(h, cycle);
		};
#if USE_LOG_FILE
		module.play_record_data = [](const tagZQDBRecordHead* head, const tagZQDBRecordBuf* data, uint8_t count) -> size_t {
			switch (head->type)
			{
			case 0: {
				if (data && count == 1) {
					if (data[0].len == sizeof(CThostFtdcDepthMarketDataField)) {
						auto& inst = MDMgr::Inst();
						inst.service().post(boost::bind(&MDMgr::update_data, &inst, *(const CThostFtdcDepthMarketDataField*)data[0].buf));
						return 1;
					}
				}
			} break;
			}
			return 0;
		};
#else
		module.save_record = []() {
			MDMgr::Inst().save_record();
		};
		module.test_record = [](uint32_t* date, uint32_t* time) {
			MDMgr::Inst().test_record(*date, *time);
		};
#endif
		g_ctp_module = ZQDBRegisterModule(&module, all_exchange, all_exchange_count, all_exchange, all_exchange_count);
		ASSERT(g_ctp_module);
		g_module_info = (tagModuleInfoEx*)ZQDBGetValue(g_ctp_module);

		return true;
	}

	bool Manager::start()
	{
		MDMgr::Inst().start();
		TDMgr::Inst().start();
		return true;
	}

	void Manager::run()
	{
		MDMgr::Inst().run();
		TDMgr::Inst().run();
	}

	void Manager::stop(size_t flags)
	{
		//LOG4I(STR_MODULE_NAME " stop");

		TDMgr::Inst().stop();

		MDMgr::Inst().stop();

		if (flags & ZQDB_STOP_FLAG_CLOSE) {
			//记录信息，这样交易日切换就不用再收盘了
			g_module_info->closeday = g_module_info->tradingday;
			info_.put("closeday", g_module_info->closeday);
			if (!ZQDBIsRPC()) {
				//RPC都会从远程更新info，只有单机或者服务器才需要一直维护info
				save_info();
			}
		}

		LOGXXX_TERM();

		google::protobuf::ShutdownProtobufLibrary();
	}

	void Manager::on_normal(bool new_trading_day)
	{
		if (ZQDBIsDisable(g_ctp_module)) {
			ZQDBEnable(g_ctp_module);
			LOG4I("g_ctp_module is disable, enable it");
		}
	}

	void Manager::begin_new_tradingday()
	{
		//先清理模块
		ZQDBBeginModuleNewTradingDay(g_ctp_module, 0);
		TDMgr::Inst().begin_new_tradingday();
		MDMgr::Inst().begin_new_tradingday();
	}

	void Manager::init_new_tradingday()
	{
		//先清理模块（用户、持仓、委托、成交等...）
		ZQDBDoModuleNewTradingDayClear(g_ctp_module, CLEAR_TRADE_DATA);
		//再清理交易
		TDMgr::Inst().clear_new_tradingday();
		//再清理行情
		MDMgr::Inst().clear_new_tradingday();
		//再初始化行情
		MDMgr::Inst().init_new_tradingday();
		//再初始化交易
		TDMgr::Inst().init_new_tradingday();
	}

	void Manager::end_new_tradingday()
	{
		//完成行情初始化
		MDMgr::Inst().end_new_tradingday();
		//完成交易初始化
		TDMgr::Inst().end_new_tradingday();
		//
		g_module_info->closeday = g_module_info->tradingday;
		info_.put("closeday", g_module_info->closeday);
		g_module_info->tradingday = MDMgr::Inst().tradingday();
		info_.put("tradingday", g_module_info->tradingday);
		//
		save_info();
		//完成模块清理
		ZQDBEndModuleNewTradingDay(g_ctp_module, 0);
		//
		on_normal(true);
	}


